﻿package com.floorplanner.lib3ds
{
	import com.floorplanner.lib3ds.*;
	import com.floorplanner.lib3ds.data.*;
	
	public class Lib3dsMesh extends Lib3dsCore
	{
		public var user:Lib3dsUserData;
		public var next:Lib3dsMesh;
		public var name:String; //[64];
		public var color:int;
		public var matrix:Array;
		public var points:int;
		public var pointL:Array;
		public var flags:int;
		public var flagL:Array;
		public var texels:int;
		public var texelL:Array;
		public var faces:int;
		public var faceL:Array;
		public var box_map:Lib3dsBoxMap;
		public var map_data:Lib3dsMapData;
		
		public function Lib3dsMesh()
		{
			this.pointL = new Array();
			this.faceL = new Array();
			this.flagL = new Array();
			this.texelL = new Array();
			
			this.points = this.flags = this.texels = this.faces = 0;
			this.matrix = new Array();
		}
		
		/**
		 * 
		 */
		public function read( io:Lib3dsIO, name:String = "" ):Boolean 
		{
			var c:Lib3dsChunk = Lib3dsChunk.read( io );
			var chunk:uint = 0;
			var i:int, j:int, k:int;
			
			this.name = name;
				
			if( c.chunk != Lib3dsChunk.N_TRI_OBJECT )
			{
				throw new Error("readMesh => chunk is not of type N_TRI_OBJECT!");
			}
					
			chunk = c.next( io );
			
			while( chunk != 0 )
			{
				switch( chunk )
				{
					case Lib3dsChunk.MESH_MATRIX:
						var matrix:Array = new Array();
						for( i = 0; i < 4; i++ )
						{
							matrix[i] = new Array();
							for( j = 0; j < 3; j++ )
							{
								matrix[i][j] = io.readFloat();
							}
							matrix[i][3] = 0;
						}
						matrix[3][3] = 1.0;
						debug("readMesh => MESH_MATRIX: \n\t" + matrix.join("\n\t"));
						this.matrix = matrix.concat();
						break;
					case Lib3dsChunk.MESH_COLOR:
						this.color = io.readByte();
						debug("readMesh => MESH_COLOR: 0x" + this.color.toString(16));
						break;
					case Lib3dsChunk.POINT_ARRAY:
						this.points = io.readShort();
						this.pointL = new Array();
						debug("readMesh => POINT_ARRAY " + this.points);
						for( i = 0; i < this.points; i++ )
						{
							var pts:Array = new Array();
							for( j = 0; j < 3; j++ )
							{
								pts.push( io.readFloat() );
							}
							
							this.pointL.push( [pts[0], pts[1], pts[2]] );
						}
						break;
					case Lib3dsChunk.POINT_FLAG_ARRAY:
						debug("readMesh => POINT_FLAG_ARRAY");
						this.flags = io.readShort();
						this.flagL = new Array();
						for( i = 0; i < this.flags; ++i )
						{
							this.flagL.push( io.readShort() );
						}
						break;
					case Lib3dsChunk.FACE_ARRAY:
						debug("readMesh => FACE_ARRAY");
						c.reset( io );
						readFaceArray( io );
						break;
					case Lib3dsChunk.MESH_TEXTURE_INFO:
						debug("readMesh => MESH_TEXTURE_INFO");
						break;
					case Lib3dsChunk.TEX_VERTS:
						this.texels = io.readShort();
						this.texelL = new Array();
						if( this.texels )
						{
							debug("readMesh => TEX_VERTS " + this.texels);
							for( i = 0; i < this.texels; ++i )
							{
								var u:Number = io.readFloat();
								var v:Number = io.readFloat();
								this.texelL.push( [u, v] );
							}
						}
						break;
					default:
						debug("readMesh -> unknown chunk: 0x" + c.chunk.toString(16) );
						break;
				}
				chunk = c.next( io );
			}
			
			c.readEnd( io );
			
			// build normals
			for( j = 0; j < this.faces; ++j )
			{
				var idx1:uint = Lib3dsFace(this.faceL[j]).points[0];
				var idx2:uint = Lib3dsFace(this.faceL[j]).points[1];
				var idx3:uint = Lib3dsFace(this.faceL[j]).points[2];
				
				var va:Array = this.pointL[idx1];
				var vb:Array = this.pointL[idx2];
				var vc:Array = this.pointL[idx3];
				
				/*
				var ab:Vector = va.subtract(vb);
				var cb:Vector = vc.subtract(vb);
				
				Lib3dsFace(this.faceL[j]).normal = cb.cross(ab);
				Lib3dsFace(this.faceL[j]).normal.normalize();
				//debug( "normal: " + Lib3dsFace(this.faceL[j]).normal );
				*/
			}
			
			return true;
		}

		/**
		 * 
		 */
		private  function readFaceArray( io:Lib3dsIO ):Boolean 
		{
			var c:Lib3dsChunk = Lib3dsChunk.read( io );
			var chunk:uint = 0;
			var i:int, j:int;
			
			if( c.chunk != Lib3dsChunk.FACE_ARRAY )
			{
				throw new Error("readFaceArray => chunk is not of type FACE_ARRAY!");
			}
			
			this.faces = io.readUnsignedShort();
			this.faceL = new Array();
			
			debug("readFaceArray #faces: " + this.faces);
							
			for( i = 0; i < this.faces; ++i ) 
			{				
				var face:Lib3dsFace = new Lib3dsFace();
				face.points.push( io.readShort() );
				face.points.push( io.readShort() );
				face.points.push( io.readShort() );
				face.flags = io.readShort();
				
				this.faceL.push( face );
			}
			
			c.cur = io.position;
			
			chunk = c.next( io );
			while( chunk != 0 )
			{
				switch( chunk )
				{
					case Lib3dsChunk.SMOOTH_GROUP:
						debug("readFaceArray -> SMOOTH_GROUP");
						for( i = 0; i < this.faces; ++i )
						{
							Lib3dsFace(this.faceL[fid]).smoothing = io.readUnsignedShort();
						}
						break;
					case Lib3dsChunk.MSH_MAT_GROUP:
						var matgroup:String = io.readString();
						var f:int = io.readShort();
						debug("readFaceArray -> MSH_MAT_GROUP " + f + " " + matgroup);
						for( i = 0; i < f; ++i )
						{
							var fid:int = io.readShort();
							if( this.faceL[fid] )
							{
								Lib3dsFace(this.faceL[fid]).material = matgroup;
							}
						}
						break;
					case Lib3dsChunk.MSH_BOXMAP:
						debug("readFaceArray -> MSH_BOXMAP");
						this.box_map = new Lib3dsBoxMap();
						this.box_map.front = io.readString();
						this.box_map.back = io.readString();
						this.box_map.left = io.readString();
						this.box_map.right = io.readString();
						this.box_map.top = io.readString();
						this.box_map.bottom = io.readString();
						break;
					default:
						debug("readFaceArray -> unknown chunk: 0x" + chunk.toString(16) );
						break;
				}
				chunk = c.next( io );
			}
			return true;
		}
	}
}
